package com.yunduansing.demo.service.impl;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.yunduansing.demo.exception.MyException;
import com.yunduansing.demo.filter.JwtAuthenticationToken;

import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.www.NonceExpiredException;

import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.factory.annotation.Autowired;

import java.util.Calendar;

@Slf4j
public class JwtAuthenticationProvider implements AuthenticationProvider {
    private final String CACHE_KEY_PREFIX = "token:";
    @Autowired
    private RedisTemplate redisTemplate;

    private AuthUserService userService;

    public JwtAuthenticationProvider(AuthUserService userService) {
        this.userService = userService;
    }

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        DecodedJWT jwt = ((JwtAuthenticationToken) authentication).getToken();
        if (jwt.getExpiresAt().before(Calendar.getInstance().getTime()))
            throw new NonceExpiredException("Token expires");
        String username = jwt.getSubject();
        UserDetails user=null;
        try {
            user = userService.getUserLoginInfo(username);
        } catch (MyException e1) {
            log.error("获取登录信息失败。", e1);
            e1.printStackTrace();
        }
        if(user == null || user.getPassword()==null)
            throw new NonceExpiredException("Token expires");
        var salt=redisTemplate.opsForValue().get(CACHE_KEY_PREFIX+username);
        if(salt==null){
            throw new NonceExpiredException("Token expires");
        }
        String encryptSalt = salt.toString();//user.getPassword();
        try {
            Algorithm algorithm = Algorithm.HMAC256(encryptSalt);
            JWTVerifier verifier = JWT.require(algorithm)
                    .withSubject(username)
                    .build();
            verifier.verify(jwt.getToken());
        } catch (Exception e) {
            throw new BadCredentialsException("JWT token verify fail", e);
        }
        JwtAuthenticationToken token = new JwtAuthenticationToken(user, jwt, user.getAuthorities());
        return token;
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return authentication.isAssignableFrom(JwtAuthenticationToken.class);
    }

}
